package com.lvhr.rpc.fault.retry;

import com.github.rholder.retry.*;
import com.lvhr.rpc.config.RetryStrategyConfig;
import com.lvhr.rpc.config.RpcConfig;
import com.lvhr.rpc.model.RpcResponse;
import lombok.extern.slf4j.Slf4j;

import javax.naming.ServiceUnavailableException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 指数退避策略实现
 */
@Slf4j
public class ExponentialBackoffRetryStrategy implements RetryStrategy {

    private RetryStrategyConfig config;

    /**
     * 指数重试
     *
     * @param callable
     * @return
     * @throws ExecutionException
     * @throws RetryException
     */
    @Override
    public RpcResponse doRetry(Callable<RpcResponse> callable) throws ExecutionException, RetryException {
        Retryer<RpcResponse> retryer = RetryerBuilder.<RpcResponse>newBuilder()
                .retryIfExceptionOfType(Exception.class)
                .withWaitStrategy(createWaitStrategy())
                .withStopStrategy(StopStrategies.stopAfterAttempt(config.getMaxAttempts()))
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.warn("RPC调用重试中 - 第{}次重试, 距首次重试间隔: {}ms ",
                                attempt.getAttemptNumber(),
                                attempt.getAttemptNumber() - 1 == 0 ? 0 : attempt.getDelaySinceFirstAttempt());
                    }

                })
                .build();
        return retryer.call(callable);
    }
    /**
     * 等待策略
     *
     * @return
     */
    private WaitStrategy createWaitStrategy() {
        // 参数校验
        if (config.getInitialIntervalMs() <= 0 ||
                config.getMaxIntervalMs() <= 0 ||
                config.getJitterFactor() <= 0 ||
                config.getMultiplier() <= 1.0) {
            throw new IllegalArgumentException("Invalid retry strategy configuration");
        }

        // 参数提取
        final long initialIntervalMs = config.getInitialIntervalMs();
        final long maxIntervalMs = config.getMaxIntervalMs();
        final double jitterFactor = config.getJitterFactor();
        final double multiplier = config.getMultiplier();

        // 计算抖动范围
        final long minJitterMs = (long) (initialIntervalMs * 0.1);
        final long maxJitterMs = (long) (initialIntervalMs * jitterFactor);
        log.info("初始化RPC重试策略: 基础间隔={}ms, 最大间隔={}ms, 乘数={}, 抖动因子={}",
                initialIntervalMs, config.getMaxIntervalMs(), multiplier, config.getJitterFactor());
        // 组合策略
        return WaitStrategies.join(
                // 指数退避(重试间隔从initialIntervalMs开始，每次重试的间隔会指数增长)
                WaitStrategies.exponentialWait(
                        initialIntervalMs,
                        maxIntervalMs,
                        TimeUnit.MILLISECONDS),

                // 随机抖动
                WaitStrategies.randomWait(
                        minJitterMs, TimeUnit.MILLISECONDS,
                        maxJitterMs, TimeUnit.MILLISECONDS
                )
        );
    }



    /**
     * 初始化
     *
     * @param config
     */
    @Override
    public void init(RpcConfig config) {
        this.config = config.getRetryStrategyConfig();
        validateConfig();
    }


    private void validateConfig() {
        if (config.getInitialIntervalMs() <= 0 || config.getMaxIntervalMs() <= 0) {
            throw new IllegalArgumentException("Interval must be positive");
        }
        if (config.getMultiplier() < 1.0) {
            throw new IllegalArgumentException("Multiplier must be >= 1.0");
        }
        if (config.getMaxAttempts() < 1) {
            throw new IllegalArgumentException("Max attempts must be >= 1");
        }
        if (config.getJitterFactor() < 0 || config.getJitterFactor() > 1) {
            throw new IllegalArgumentException("Jitter factor must be between 0 and 1");
        }
    }

}
